package lar.game.physics;

public class Vector
{
	private final long x;
	private final long y;
	
	private static long Round(double d)
	{
		return Math.round(d * 1000.0);
	}
	
	private static double RetVal(long i)
	{
		return i / 1000.0;
	}
	
	public Vector(double x, double y)
	{
		this.x = Round(x);
		this.y = Round(y);
	}
	
	public Vector Normalize()
	{
		return new Vector(RetVal(x) / GetR(), RetVal(y) / GetR());
	}
	
	public Vector(Rotation rotation, double size)
	{
		this.x = Round(rotation.ElementX() * size);
		this.y = Round(rotation.ElementY() * size);
	}
	
	public Vector(Vector other)
	{
		this.x = other.x;
		this.y = other.y;
	}
	
	public Vector (String init)
	{
		String[] strArr = init.split("_");
		x = Long.parseLong(strArr[0]);
		y = Long.parseLong(strArr[1]);
	}
	
	public String Serialize()
	{
		return "" + x + "_" + y;
	}
	
	public Vector Add(Vector other)
	{
		return new Vector(RetVal(x) + other.GetX(), RetVal(y) + other.GetY());
	}
	
	public Vector Multiply(double value)
	{
		return new Vector(RetVal(x) * value, RetVal(y) * value);
	}
	
	/**
	 * Returns your projection on another vector.
	 * @param other - The vector to project on to.
	 * @return The projection vector.
	 */
	public Vector Projection(Vector other)
	{
		if(other.GetR()<=0) return new Vector(0, 0);
		return other.Multiply((GetT().Cos(other.GetT())) * GetR() / other.GetR());
	}
	
	/**
	 * Returns your rejection on another vector.
	 * @param other - The vector to reject on to.
	 * @return The rejection vector.
	 */
	public Vector Rejection(Vector other)
	{
		return other.Add(Projection(other).Multiply(-1));
	}
	
	/**
	 * Returns the length of your projection on another vector.
	 * @param other - The vector to project on to.
	 * @return Your projection's length.
	 */
	public double ProjectionR(Vector other)
	{
		if(other.GetR()<=0) return 0;
		return (GetT().Cos(other.GetT())) * GetR();
	}
	
	/**
	 * Returns a vector needed to reflect the target vector.
	 * @param target - The vector incoming.
	 * @return The direction change for the incoming vector.
	 */
	public Vector Reflect(Vector target)
	{
		return target.Projection(this).Multiply(-2);
	}
	
	public double GetX()
	{
		return RetVal(x);
	}
	
	public double GetY()
	{
		return RetVal(y);
	}
	
	public double GetR()
	{
		return Math.sqrt(RetVal(x)*RetVal(x)+RetVal(y)*RetVal(y));
	}
	
	public Rotation GetT()
	{
		return new Rotation(this);
	}
	
	public Vector MirrorX()
	{
		return new Vector(-RetVal(x), RetVal(y));
	}
	
	public Vector MirrorY()
	{
		return new Vector(RetVal(x), -RetVal(y));
	}
}
